package com.llh.uua.util

import com.llh.uua.conf.properties.AppProperties
import io.jsonwebtoken.*
import io.jsonwebtoken.io.Decoders
import io.jsonwebtoken.security.Keys
import org.springframework.security.core.userdetails.UserDetails
import org.springframework.stereotype.Component
import java.security.Key
import java.util.*
import javax.crypto.SecretKey
import kotlin.streams.toList

private var accessKey: SecretKey = Keys.secretKeyFor(SignatureAlgorithm.HS512)
private var refreshKey: SecretKey = Keys.secretKeyFor(SignatureAlgorithm.HS512)
private var properties: AppProperties = AppProperties()

/**
 * [Jwt_authority_key] jwt中授权信息的key值
 */
const val JWT_AUTHORITY_KEY = "authorities"

@Component
class RegisterJwtUtil(private val app: AppProperties) {

    init {
        properties = app
        accessKey = Keys.hmacShaKeyFor(Decoders.BASE64.decode(app.jwt.accessKey))
        refreshKey = Keys.hmacShaKeyFor(Decoders.BASE64.decode(app.jwt.refreshKey))
    }
}

/**
 * 创建AccessToken
 */
fun createAccessToken(userDetails: UserDetails): String {
    return createToken(userDetails, properties.jwt.accessExp, accessKey)
}

/**
 * 创建RefreshToken
 */
fun createRefreshToken(userDetails: UserDetails): String {
    return createToken(userDetails, properties.jwt.refreshExp, refreshKey)
}

/**
 * 生成JWT
 * @param userDetails 用户信息
 * @param expTime 过期时间
 * @param signKey 签名
 */
fun createToken(userDetails: UserDetails, expTime: Long, signKey: Key): String {
    return Jwts
        .builder()
        .setId(properties.jwt.appId)
        .setSubject(userDetails.username)
        .claim(JWT_AUTHORITY_KEY, userDetails.authorities.stream().map { it.authority }.distinct().toList())
        .setIssuedAt(Date(System.currentTimeMillis()))
        .setExpiration(Date(System.currentTimeMillis() + expTime))
        .signWith(signKey, SignatureAlgorithm.HS256)
        .compact()
}

/**
 * 解析[accessToken]
 */
fun parseClaimsAccessToken(accessToken: String): Claims? {
    return parseClaims(accessToken, accessKey)
}

/**
 * 使用给定的[signKey]解析[token]，并获取jwt主体
 */
fun parseClaims(token: String, signKey: Key): Claims? {
    return Jwts.parserBuilder()
        .setSigningKey(signKey)
        .build()
        .parseClaimsJws(token)
        .body
}

/**
 * 验证[token]-AccessToken
 */
fun validateAccessToken(token: String): Boolean {
    return validateToken(token, accessKey)
}

/**
 * 验证[token]-RefreshToken
 */
fun validateRefreshToken(token: String): Boolean {
    return validateToken(token, refreshKey)
}

/**
 * 使用给定的[signKey]解析[token]
 */
fun validateToken(token: String, signKey: Key): Boolean {
    return try {
        Jwts.parserBuilder()
            .setSigningKey(signKey)
            .build()
            .parseClaimsJws(token)
        true
    } catch (e: Exception) {
        false
    }
}

/**
 * 使用RefreshToken[token]构建AccessToken
 */
fun buildAccessTokenWithRefreshToken(token: String): String? {
    return parseClaims(token, refreshKey)?.let {
        Jwts.builder()
            .setClaims(it)
            .setExpiration(Date(System.currentTimeMillis() + properties.jwt.refreshExp))
            .signWith(refreshKey, SignatureAlgorithm.HS256)
            .compact()
    }
}